home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
BBS-Archive
/
Comm
/
AmiTCP30b2.lha
/
src
/
amitcp
/
kern
/
amiga_config.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-12-20
|
17KB
|
664 lines
RCS_ID_C="$Id: amiga_config.c,v 1.21 1993/12/20 18:04:11 jraja Exp $";
/*
* Copyright © 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
* Helsinki University of Technology, Finland.
* All rights reserved.
*
* amiga_config.c --- Configuring AmiTCP/IP
*
* Created : Thu Apr 22 12:27:04 1993 ppessi
* Last modified: Mon Dec 20 10:36:28 1993 jraja
*
* $Log: amiga_config.c,v $
* Revision 1.21 1993/12/20 18:04:11 jraja
* Added missing semicolon + const to parsefile()s first argument.
*
* Revision 1.20 1993/12/20 08:41:22 jraja
* Added external declaration for AmiTCP_Task.
*
* Revision 1.19 1993/12/20 08:25:57 jraja
* Changed rexx function parsing to use function table instead of switch.
* Added handling for the new "KILL" keyword (sendbreak()).
*
* Revision 1.18 1993/11/06 23:51:22 ppessi
* Changed sprintf() to csprintf()
*
* Revision 1.17 1993/06/04 11:16:15 jraja
* Fixes for first public release.
*
* Revision 1.16 1993/06/03 16:38:23 jraja
* Added VAR_ENUM variable type.
*
* Revision 1.15 1993/05/31 23:27:31 jraja
* Removed Key_CONN and the associated getsockets() call.
*
* Revision 1.14 1993/05/29 21:10:15 jraja
* Added ERR_NOWRITE error, changed return values to symbolic RETURN_XXXX,
* added check for setting only configuration-writeable variables,
* cleared return value after SET, Added error reporting to config-file
* parsing, now just passes by syntax and parse-errors,
* writes template if command line cannot be parsed.
*
* Revision 1.13 1993/05/17 01:07:47 ppessi
* Changed RCS version.
*
* Revision 1.12 1993/05/16 00:13:34 jraja
* Changed one return value from 20 to RETURN_FAIL.
*
* Revision 1.11 93/05/14 11:35:40 11:35:40 ppessi (Pekka Pessi)
* Cleaned up variables. All netdb special stuff is moved to the amiga_netdb.c.
*
* Revision 1.10 93/05/05 16:09:45 16:09:45 puhuri (Markus Peuhkuri)
* Fixes for final demo.
*
* Revision 1.9 93/05/04 12:18:00 12:18:00 jraja (Jarno Tapio Rajahalme)
* fix.
*
* Revision 1.8 93/05/02 18:01:44 18:01:44 jraja (Jarno Tapio Rajahalme)
* Fixed assignment to the RDA_Source.
*
* Revision 1.7 93/05/02 17:33:43 17:33:43 jraja (Jarno Tapio Rajahalme)
* Made some of the parseroute.
*
* Revision 1.6 93/04/28 21:54:02 21:54:02 ppessi (Pekka Pessi)
* Uses now automatically generated variable table.
*
* Revision 1.5 93/04/26 20:33:47 20:33:47 puhuri (Markus Peuhkuri)
* Add configuration for logfilename and consolename.
*
* Revision 1.4 93/04/24 22:05:59 22:05:59 jraja (Jarno Tapio Rajahalme)
* Added mbuf statistics.
*
* Revision 1.3 93/04/23 21:01:01 21:01:01 puhuri (Markus Peuhkuri)
* Updated call to getsockets
*
* Revision 1.2 93/04/23 02:25:53 02:25:53 ppessi (Pekka Pessi)
* Added logging message amount an length into config variables..
*
* Revision 1.1 93/04/23 00:26:19 00:26:19 ppessi (Pekka Pessi)
* Initial revision
*/
#include <conf.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/syslog.h>
#include <sys/socket.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <netdb.h> /* pathnames */
#include <kern/amiga_includes.h>
#include <kern/amiga_config.h>
#include <kern/amiga_netdb.h>
#include <utility/tagitem.h>
#include <dos/rdargs.h>
#if __SASC
#include <proto/dos.h>
#elif __GNUC__
#include <inline/dos.h>
#endif
#include <net/route.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
#include <netinet/tcp.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
/* External functions */
int inet_aton(register const char *cp, struct in_addr *addr);
int ultoa(unsigned long ul,char *buffer);
extern struct Task *AmiTCP_Task; /* referenced by sendbreak() */
/* Parsing error messages */
UBYTE ERR_UNKNOWN[] = "Unknown command\n";
UBYTE ERR_ILLEGAL_VAR[] = "%s: unknown variable %s\n";
UBYTE ERR_ILLEGAL_IND[] = "%s: unknown index %s\n";
UBYTE ERR_SYNTAX[] = "Syntax error\n";
UBYTE ERR_TOO_LONG[] = "Result too long\n";
UBYTE ERR_MEMORY[] = "Memory exhausted\n";
UBYTE ERR_NONETDB[] = "No active net database\n";
UBYTE ERR_VALUE[] = "Illegal value\n";
UBYTE ERR_NOWRITE[] = "%s: Variable %s is not writeable\n";
/* Array of parsing functions. Note that the order is same as in the
* enum keyword.
*/
var_f rexx_parse_funs[] = {
getvalue, /* KEY_QUERY */
setvalue, /* KEY_SET */
readfile, /* KEY_READ */
parseroute, /* KEY_ROUTE */
do_netdb, /* KEY_ADD */
reset_netdb, /* KEY_RESET */
sendbreak /* KEY_KILL */
};
/*
* Parse a Rexx command line
*/
LONG
parseline(struct CSource *csarg, UBYTE **errstrp, struct CSource *res)
{
UBYTE Buffer[KEYWORDLEN];
enum keyword keyword;
/* Parse the command keyword */
LONG item = ReadItem(Buffer, sizeof(Buffer), csarg);
if (item == 0)
return RETURN_OK;
else if (item < 0) {
*errstrp = ERR_SYNTAX;
return RETURN_WARN;
}
if ((keyword = FindArg((UBYTE*)REXXKEYWORDS, Buffer)) < 0) {
*errstrp = ERR_UNKNOWN;
return RETURN_WARN;
}
return rexx_parse_funs[keyword](csarg, errstrp, res);
}
/*
* 'Parse' the "KILL" command
*/
LONG
sendbreak(struct CSource *args, UBYTE **errstrp, struct CSource *res)
{
Signal(AmiTCP_Task, SIGBREAKF_CTRL_C);
return RETURN_OK;
}
extern UBYTE *KW_VARS;
extern struct cfg_variable variables[];
/*
* Parse the "Query" commands
*/
LONG
getvalue(struct CSource *args, UBYTE **errstrp, struct CSource *res)
{
UBYTE Buffer[KEYWORDLEN];
WORD var, index;
LONG vlen;
UBYTE *value = NULL;
Buffer[0] = '\0';
while ((var = ReadItem(Buffer, sizeof(Buffer), args)) > 0) {
if ((var = FindArg(KW_VARS, Buffer)) < 0 ||
(variables[var].flags & VF_READ) != VF_READ) {
res->CS_CurChr = 0;
csprintf(res, ERR_ILLEGAL_VAR, "getvalue", Buffer);
*errstrp = res->CS_Buffer;
return RETURN_WARN;
} else {
if (variables[var].flags & VF_TABLE) {
if (ReadItem(Buffer, sizeof(Buffer), args) <= 0 ||
(index = FindArg((UBYTE *)variables[var].index, Buffer)) < 0) {
res->CS_CurChr = 0;
csprintf(res, ERR_ILLEGAL_IND, "getvalue", Buffer);
*errstrp = res->CS_Buffer;
return RETURN_WARN;
}
} else {
index = 0;
}
switch (variables[var].type) {
case VAR_FUNC:
if (variables[var].value) {
if (vlen = (*(var_f)(variables[var].value))(args, errstrp, res))
return vlen;
} else {
*errstrp = ERR_ILLEGAL_VAR;
return RETURN_ERROR;
}
value = (char *)1; /* successful flag.. */
continue; /* while() */
case VAR_LONG:
case VAR_FLAG:
vlen = ultoa(((LONG*)variables[var].value)[index], Buffer);
value = Buffer;
break;
case VAR_STRP:
value = ((UBYTE **)variables[var].value)[index];
vlen = strlen(value);
break;
case VAR_INET:
{
ULONG s_addr =
((struct in_addr *)variables[var].value)[index].s_addr;
vlen = sprintf(Buffer, "%ld.%ld.%ld.%ld",
(s_addr>>24) & 0xff, (s_addr>>16) & 0xff,
(s_addr>>8) & 0xff, s_addr & 0xff);
value = Buffer;
}
break;
case VAR_ENUM:
{
ULONG i = 0, nth;
STRPTR p;
nth = ((ULONG*)variables[var].value)[index];
/*
* search nth keyword from the template
*/
value = (STRPTR)variables[var].notify;
while (*value && i < nth)
if (*value++ == ',')
i++;
if (i < nth) { /* value not found */
*errstrp = ERR_VALUE;
return RETURN_ERROR;
}
/*
* find the length of the answer
*/
p = value;
while(*p && *p != '=' && *p != ',')
p++;
vlen = p - value;
}
break;
}
/* prepend by space? */
if (res->CS_CurChr)
res->CS_Buffer[res->CS_CurChr++] = ' ';
if (vlen + res->CS_CurChr > res->CS_Length) {
*errstrp = ERR_TOO_LONG;
return RETURN_ERROR;
}
bcopy(value, res->CS_Buffer + res->CS_CurChr, (WORD)vlen);
res->CS_CurChr += vlen;
}
}
if (!value || var != ITEM_NOTHING) {
*errstrp = ERR_SYNTAX;
return RETURN_WARN;
}
res->CS_Buffer[res->CS_CurChr] = '\0';
return RETURN_OK;
}
/*
* Parse the "Set" commands
*
* TODO: notifications for VAR_INET;
*/
LONG
setvalue(struct CSource *args, UBYTE **errstrp, struct CSource *res)
{
UBYTE Buffer[KEYWORDLEN];
LONG BufLen = sizeof(Buffer);
LONG vlen, item;
WORD var, index;
UBYTE *value;
void *dp = NULL; /* pointer to data item */
Buffer[0] = '\0';
while ((item = ReadItem(Buffer, BufLen, args)) > 0) {
if ((var = FindArg(KW_VARS, Buffer)) < 0 ||
(!(variables[var].flags & VF_WRITE) &&
(initialized || !(variables[var].flags & VF_CONF)))) {
res->CS_CurChr = 0;
csprintf(res, (var < 0) ? ERR_ILLEGAL_VAR : ERR_NOWRITE,
"setvalue", Buffer);
*errstrp = res->CS_Buffer;
return RETURN_WARN;
} else {
if (variables[var].flags & VF_TABLE) {
if (ReadItem(Buffer, BufLen, args) <= 0 ||
(index = FindArg((UBYTE *)variables[var].index, Buffer)) < 0) {
res->CS_CurChr = 0;
csprintf(res, ERR_ILLEGAL_IND, "setvalue", Buffer);
*errstrp = res->CS_Buffer;
return RETURN_WARN;
}
} else {
index = 0;
}
if (variables[var].type != VAR_FLAG &&
*CURRENT(args) == '=')
args->CS_CurChr++;
/* If dp is different for a type,
* it must be calculated in the case statement
*/
dp = (void *)((LONG *)variables[var].value + index);
switch (variables[var].type) {
case VAR_FUNC:
if (variables[var].notify) {
if (vlen = (*(var_f)(variables[var].notify))(args, errstrp, res))
return vlen;
} else {
*errstrp = ERR_ILLEGAL_VAR;
return RETURN_ERROR;
}
break;
case VAR_LONG:
if ((vlen = StrToLong(CURRENT(args), &item)) <= 0)
goto reterr;
if (variables[var].notify)
if (!(*variables[var].notify)(dp, item)) {
*errstrp = ERR_VALUE;
return RETURN_WARN;
}
*(LONG*)dp = item;
args->CS_CurChr += vlen;
break;
case VAR_STRP:
if (ReadItem(Buffer, BufLen, args) <= 0)
goto reterr;
vlen = strlen(Buffer) + 1;
value = bsd_malloc(vlen, M_CFGVAR, M_WAITOK);
if (!value) {
*errstrp = ERR_MEMORY;
return RETURN_ERROR;
}
strcpy(value, Buffer);
if (variables[var].notify)
if (!(*variables[var].notify)(dp, (LONG) value)) {
bsd_free(value, M_CFGVAR);
*errstrp = ERR_VALUE;
return RETURN_WARN;
}
if (variables[var].flags & VF_FREE) {
bsd_free(*(UBYTE **)dp, M_CFGVAR);
}
*(UBYTE **)dp = value;
variables[var].flags |= VF_FREE;
break;
case VAR_INET:
/* Currently, nameservice can not be used */
if (ReadItem(Buffer, BufLen, args) <= 0)
goto reterr;
if (!inet_aton(Buffer, (struct in_addr *)dp))
goto reterr;
break;
case VAR_ENUM:
if (ReadItem(Buffer, BufLen, args) <= 0)
goto reterr;
/*
* Match the item against the template. The value is the index of
* the matching keyword, if one is found.
*/
if ((vlen = FindArg((STRPTR)variables[var].notify, Buffer)) < 0)
goto reterr;
/*
* Set the new value. Note that there is no notify function, since
* the notify field was used for the template.
*/
*(LONG *)dp = vlen;
break;
}
}
}
if (item != ITEM_NOTHING) {
reterr:
*errstrp = ERR_SYNTAX;
return RETURN_WARN;
}
#define DONE "Done."
bcopy(DONE, res->CS_Buffer + res->CS_CurChr, sizeof(DONE));
res->CS_CurChr += sizeof(DONE);
res->CS_Buffer[res->CS_CurChr] = '\0';
return RETURN_OK;
}
/*
* SET WITH a file
*/
LONG read_sets(struct CSource *args, UBYTE **errstrp, struct CSource *res)
{
UBYTE * buf = res->CS_Buffer;
if (ReadItem(buf, res->CS_Length, args) < 0) {
*errstrp = ERR_SYNTAX;
return RETURN_WARN;
} else {
return parsefile(buf, errstrp, res);
}
}
/*
* Parse a 'WITH' command
*/
LONG
readfile(struct CSource *args, UBYTE **errstrp, struct CSource *res)
{
*errstrp = "readfile() is currently unimplemented\n";
return RETURN_WARN;
}
#define CMDLINETEMP "WITH/K,NOO=NOCONFIG/S,DEBUG/S"
#define CL_WITH 0
#define CL_NOCFG 1
#define CL_DEBUG 2 /* Currently default, does nothing */
#define CL_SIZE 3
/*
* Read command file
*/
LONG
parsefile(UBYTE const *name, UBYTE **errstrp, struct CSource *res)
{
LONG retval = RETURN_OK, ioerr = 0;
struct CSource arg;
int line = 0;
BPTR fh;
UBYTE *buf = AllocMem(CONFIGLINELEN, MEMF_PUBLIC);
if (buf) {
arg.CS_Buffer = buf;
if (fh = Open(name, MODE_OLDFILE)) {
while (FGets(fh, buf, CONFIGLINELEN)) {
line++;
if (*buf == '#')
continue;
arg.CS_Length = strlen(buf);
arg.CS_CurChr = 0;
retval = setvalue(&arg, errstrp, res);
if (retval == RETURN_OK)
continue;
if (retval != RETURN_WARN) /* severe error */
break;
/* Print the error to the "stdout" */
Printf("%s: line %ld, col %ld: %s",
name, line, arg.CS_CurChr, *errstrp);
retval = RETURN_OK;
}
/* Check file error */
ioerr = IoErr();
Close(fh);
} else {
ioerr = IoErr();
}
if (ioerr) {
Fault(ioerr, name, res->CS_Buffer, res->CS_Length);
*errstrp = res->CS_Buffer;
retval = RETURN_ERROR;
}
FreeMem(buf, CONFIGLINELEN);
} else {
*errstrp = ERR_MEMORY;
retval = RETURN_FAIL;
}
return retval;
}
/*
* Read command line arguments and configuration file
*/
BOOL
readconfig(void)
{
UBYTE result[REPLYBUFLEN + 1]; /* for error returns */
struct CSource res;
struct RDArgs *rdargs = NULL;
LONG args[CL_SIZE] = { 0 };
UBYTE *errstr;
LONG error = 0;
res.CS_Buffer = result;
res.CS_Length = sizeof(result);
res.CS_CurChr = 0;
/* Parse command line arguments, if any */
rdargs = ReadArgs(CMDLINETEMP, args, NULL);
if (!rdargs) {
Printf("Argument error. Template: %s\n", CMDLINETEMP);
return FALSE;
}
if (!args[CL_NOCFG])
/* Read default configuration file */
error = parsefile(_PATH_AMITCP_CONFIG, &errstr, &res);
if (!error && args[CL_WITH])
/* Read given file */
error = parsefile((STRPTR)args[CL_WITH], &errstr, &res);
FreeArgs(rdargs);
if (error)
Printf("AmiTCP/IP Configuration: %s\n", errstr);
return ((BOOL)!error);
}
#if 0
/*
* The order of following keywords is selected to reflect the order of
* route message numbers in <net/route.h>, so DO NOT CHANGE THE ORDER.
*/
static STRPTR KW_ROUTE_CMDS =
"RESET,ADD,DELETE,CHANGE,GET";
static STRPTR ROUTE_TEMPLATE =
"NET/S,HOST/S,DESTINATION/A,GATEWAY/A,INTERFACE/S,HCNT=HOPCOUNT/K/N";
enum route_template
{ ROUTE_NET, ROUTE_HOST, ROUTE_DESTINATION, ROUTE_GATEWAY, ROUTE_INTERFACE,
ROUTE_HOPCOUNT, ROUTE_TEMPLATE_SIZE };
#endif /* 0 */
/*
* Parse route command
*/
LONG
parseroute(struct CSource *args, UBYTE **errstrp, struct CSource *res)
{
#if 1
*errstrp = "ROUTE not implemented.\n";
return RETURN_FAIL;
#else
UBYTE Buffer[KEYWORDLEN];
LONG BufLen = sizeof(Buffer);
struct RDArgs *rdargs;
LONG argArray[ROUTE_TEMPLATE_SIZE] = { 0 };
LONG vlen, item;
WORD index;
UBYTE *value;
void *dp = NULL; /* pointer to data item */
int req, flags = 0;
struct sockaddr_in destination, gateway, netmask;
int error;
Buffer[0] = '\0';
if ((item = ReadItem(Buffer, BufLen, args)) <= 0
|| (req = FindArg(KW_ROUTE_CMDS, Buffer)) < 0) {
*errstrp = ERR_SYNTAX;
return RETURN_FAIL;
}
if (req == 0) { /* RESET, delete all routes */
*errstrp = "route reset is currently unimplemented\n";
return RETURN_FAIL;
}
if (req == RTM_CHANGE) {
*errstrp = "route change is currently unimplemented\n";
return RETURN_FAIL;
}
if (req == RTM_GET) {
*errstrp = "route get is currently unimplemented\n";
return RETURN_FAIL;
}
/*
* Initialize the RDArgs structure for ReadArgs()
*/
rdargs = AllocDosObjectTags(DOS_RDARGS, TAG_END);
if (rdargs == NULL) {
*errstrp = ERR_MEMORY;
return RETURN_FAIL;
}
rdargs->RDA_Source = *args;
rdargs->RDA_DAList = NULL;
rdargs->RDA_Buffer = NULL;
rdargs->RDA_BufSiz = 0;
rdargs->RDA_ExtHelp = NULL;
rdargs->RDA_Flags = 0;
if (ReadArgs(ROUTE_TEMPLATE, argArray, rdargs) == NULL
|| (argArray[ROUTE_HOST] && argArray[ROUTE_NET])) {
FreeDosObject(DOS_RDARGS, rdargs);
*errstrp = ERR_SYNTAX;
return RETURN_FAIL;
}
/*
* Find destination host/network
*/
/* INCOMPLETE */
if (!argArray[ROUTE_INTERFACE])
flags |= RTF_GATEWAY;
if (argArray[ROUTE_HOST])
flags |= RTF_HOST;
#if 0
error = rtrequest(req, &destination, &gateway,
(flags & RTF_HOST) ? NULL : &netmask,
flags, (struct rtentry **)0);
#endif
FreeArgs(rdargs);
FreeDosObject(DOS_RDARGS, rdargs);
return RETURN_OK;
#endif
}